package com.pansoft.nfc.mifare;

import android.app.Activity;
import android.content.Context;

import com.efounder.chat.utils.CommonThreadPoolUtils;
import com.efounder.constant.EnvironmentVariable;
import com.efounder.utils.ResStringUtil;
import com.pansoft.nfc.NfcAlertUtils;
import com.pansoft.nfc.NfcCommonUtils;
import com.pansoft.nfc.acs.ApduListManager;
import com.pansoft.openplanet.R;
import com.pansoft.openplanet.bean.Account;
import com.pansoft.openplanet.bean.CardBean;
import com.pansoft.openplanet.bean.CardWalletInfo;
import com.pansoft.openplanet.db.AccountDao;
import com.pansoft.openplanet.db.CardDao;
import com.pansoft.openplanet.util.TCAccountManager;
import com.pansoft.openplanet.widget.CommonPassWordAlertDialog;
import com.utilcode.util.LogUtils;

import org.json.JSONObject;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

import static com.pansoft.nfc.NfcCommonUtils.getSectorByPosition;

/**
 * Mifare Classic nfc的管理类
 * 封装了读写卡的具体方法
 *
 * @author wang
 */
public class MCManager {

    /** nfc卡片的读写秘钥 */
    public static String CHECK_KEY = "AB158D36E793";
    private Context context;
    private MCReader reader;
    private MCStateListener mcStateListener;

    public MCManager(Context context, MCReader reader) {
        this.context = context;
        this.reader = reader;
    }

    private boolean checkReaderNull() {
        if (reader == null) {
            reader = Common.checkForTagAndCreateReader(context);
        }
        if (reader == null) {
            if (mcStateListener != null) {
                mcStateListener.onError("reader null");
            }
            return true;
        }
        return false;
    }

    /**
     * 读取0扇区数据
     * 1区块是卡号
     * 2区块是卡号
     */
    public void readUidSector() {
        if (checkReaderNull()) {
            return;
        }
        try {
            //读取0扇区，卡号等信息
            String readContent = reader.readSector(0, Common.hexStringToByteArray(CHECK_KEY), false);
            if (!NfcCommonUtils.handleUidStartData(context, readContent)) {
                return;
            }
            final String cardNo = readContent.substring(32, 64);
            final String cardType = readContent.substring(36, 40);

            //读取1扇区，存有PIN密码，使用AES加密之后的
            String password = reader.readSector(1, Common.hexStringToByteArray(CHECK_KEY), false);
            password = NfcCommonUtils.handleSecretKeyData(password);
            CommonPassWordAlertDialog commonPassWordAlertDialog = new CommonPassWordAlertDialog((Activity) context,
                    ResStringUtil.getString(R.string.star_asset_card_pin), password, new CommonPassWordAlertDialog.OnEnterClick() {
                @Override
                public void passVerifySuccess(String passWord) {
                    if (mcStateListener != null) {
                        mcStateListener.onAuthSuccess(cardNo, cardType);
                    }
                }
            });
            commonPassWordAlertDialog.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



    /**
     * 读取0扇区数据
     * 1区块是卡号
     * 2区块是卡号
     */
    public void changeCardPassword(String rawPass) {
        if (checkReaderNull()) {
            return;
        }
        try {
            String readContent = reader.readSector(0, Common.hexStringToByteArray(CHECK_KEY), false);
            LogUtils.d("头部uid", readContent);
            readContent = readContent.replace((" "), "").replace("\n", "");
            //uid卡号
            String uid = readContent.substring(0, 32);
            LogUtils.d("UID--", uid);
            final String cardNo = readContent.substring(32, 64);
            final String cardType = readContent.substring(36, 40);
            //读取1扇区，存有PIN密码，使用AES加密之后的
            String password = reader.readSector(1, Common.hexStringToByteArray(CHECK_KEY), false);
            password = NfcCommonUtils.handleSecretKeyData(password);
            if (rawPass.equals(password)) {
                //原密码相同，更改密码
                if (mcStateListener != null) {
                    mcStateListener.onAuthSuccess(cardNo, cardType);
                }
            } else {
                if (mcStateListener != null) {
                    mcStateListener.onError("WRONG_PASSWORD");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 读取0扇区数据
     * 1区块是卡号
     * 2区块是卡号
     */
    public void resetCardPassword() {
        if (checkReaderNull()) {
            return;
        }
        try {
            String readContent = reader.readSector(0, Common.hexStringToByteArray(CHECK_KEY), false);
            LogUtils.d("头部uid", readContent);
            readContent = readContent.replace((" "), "").replace("\n", "");
            //uid卡号
            String uid = readContent.substring(0, 32);
            LogUtils.d("UID--", uid);
            final String cardNo = readContent.substring(32, 64);
            final String cardType = readContent.substring(36, 40);
            if (mcStateListener != null) {
                mcStateListener.onAuthSuccess(cardNo, cardType);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 读取1扇区数据，解析验证卡内信息
     * 1扇区存储json字符{"v":"1","p":"0,1"}
     * v版本，写一次，加一；p钱包位置，逗号分隔
     *
     * @return 错误null，空卡 “”
     */
    public String readStartSector() {
        if (checkReaderNull()) {
            return null;
        }
        try {
            String readContent = reader.readSector(2, Common.hexStringToByteArray(CHECK_KEY), false);
            LogUtils.d("头部验证区", readContent);
            readContent = readContent.replace((" "), "").replace("\n", "");
            if (readContent.equals("") || readContent.equals("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")) {
                return "";
            } else {
                readContent = new String(Common.hexStringToByteArray(readContent), StandardCharsets.UTF_8).trim();
                return readContent;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 检查第一扇区卡片信息，判断是否空卡，
     * 如果已添加，判断数据是否一致
     *
     * @param startResponse 读取到的数据
     */
    public void onAddCard(final String uid, final String type, final String startResponse, final CardBean cardBean) {
        if (cardBean == null) {
            //本地无此卡，添加
            //添加卡片到服务器
            CommonThreadPoolUtils.execute(new Runnable() {
                @Override
                public void run() {
                    if (new TCAccountManager(context).addCardToServer(uid, EnvironmentVariable.getProperty("tc_ethAddress"))) {
                        ((Activity) context).runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                dealCardData(uid, type, startResponse, cardBean, false);
                            }
                        });
                    } else {
                        ((Activity) context).runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                NfcAlertUtils.showNfcFailAlert((Activity) context);
                            }
                        });
                    }
                }
            });
        } else {
            //已经绑卡
            dealCardData(uid, type, startResponse, cardBean, true);
        }

    }

    private void dealCardData(String uid, String type, String startResponse, CardBean cardBean, boolean isAdded) {
        try {
            CardDao cardDao = new CardDao(context);
            if (cardBean == null) {
                cardBean = new CardBean();
                cardBean.setUid(uid);
                cardBean.setCardType(type);
            }
            if ("".equals(startResponse)) {
                //空卡
                if (isAdded) {
                    //卡片没数据了，但是本地卡片还有，除了删除本地卡片数据库，还要删除Account数据库的
                    List<CardWalletInfo> cardWalletInfoList = cardBean.getWalletInfoList();
                    if (cardWalletInfoList != null && cardWalletInfoList.size() > 0) {
                        AccountDao accountDao = new AccountDao(context);
                        for (int i = 0; i < cardWalletInfoList.size(); i++) {
                            Account account = accountDao.getAccount(cardWalletInfoList.get(i).getAddress());
                            if (account != null) {
                                account.setEnable(false);
                                accountDao.insertOrReplace(account);
                            }
                        }
                    }
                }
                //更新start区块信息，将新的position加入
                int ver = 0;
                cardBean.setVersion(String.valueOf(ver));
                String startString = ApduListManager.parseStartData(
                        "", String.valueOf(ver));
                if (writeWallet(startString, 8, 1)) {
                    cardBean.setWalletInfoList(new ArrayList<CardWalletInfo>());
                    cardBean.setEnable(true);
                    cardDao.insertOrReplace(cardBean);
                    if (mcStateListener != null) {
                        mcStateListener.onAddSucceed();
                    }
                }
                return;
            }

            JSONObject jsonObject = new JSONObject(startResponse);
            String version = jsonObject.optString("v");
            //读取钱包位置
            String[] rawPositions = jsonObject.optString("p").split(",");
            String[] positions;
            //之前写入有错误，这里进行改正
            if (rawPositions.length > 0 && "".equals(rawPositions[0])) {
                positions = new String[rawPositions.length - 1];
                //之前写入一个空字符, 这里去掉
                System.arraycopy(rawPositions, 1, positions, 0, rawPositions.length - 1);
//                for (int i = 0; i < rawPositions.length; i++) {
//                    positions[i] = rawPositions[i + 1];
//                }
            } else {
                positions = rawPositions;
            }

            if (isAdded) {
//                if (!"".equals(version) && !version.equals(cardBean.getVersion())) {
                //卡片已添加，但是内容不一致，需更新本地数据库内容
//                if ("".equals(cardBean.getVersion()) || "0".equals(cardBean.getVersion())) {
                //本地无数据，可直接读卡复制
                //读取钱包
//                    readContent(positions, cardBean);
//                } else {
//                    //判断内容差距，选择性复制或删除
//                }
//                    return;
//                }
                if (mcStateListener != null) {
                    mcStateListener.onAddedAlready();
                }
                return;
            }
            cardBean.setVersion(version);
            if (positions.length <= 0) {
                //空卡
                cardBean.setWalletInfoList(new ArrayList<CardWalletInfo>());
                cardBean.setEnable(true);
                cardDao.insertOrReplace(cardBean);
                if (mcStateListener != null) {
                    mcStateListener.onAddSucceed();
                }
            } else {
                //读取钱包
                readContent(positions, cardBean);
            }
        } catch (Exception e) {
            e.printStackTrace();
            if (mcStateListener != null) {
                mcStateListener.onError("");
            }
        }
    }

    /**
     * 根据位置读取钱包内容
     *
     * @param positions 钱包保存的位置，1，2...
     */
    private void readContent(final String[] positions, final CardBean cardBean) {
        if (checkReaderNull()) {
            return;
        }
        CommonThreadPoolUtils.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    final String[] strings = new String[positions.length];
                    for (int i = 0; i < positions.length; i++) {
                        final StringBuilder stringBuilder = new StringBuilder();
                        //根据位置确定要读取的sector
                        int sector = getSectorByPosition(Integer.valueOf(positions[i]));
                        //一次读取5个扇区
                        if (sector <= 27) {
                            for (int j = 0; j < 5; j++) {
                                String readContent = reader.readSector(sector + j, Common.hexStringToByteArray(CHECK_KEY), false);
                                stringBuilder.append(readContent);
                            }
                        } else {
                            //一次读一个扇区
                            String readContent = reader.readSector(sector, Common.hexStringToByteArray(CHECK_KEY), false);
                            stringBuilder.append(readContent);
                        }
                        strings[i] = stringBuilder.toString();
                    }
                    ((Activity) context).runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            onHandleWalletInfo(positions, strings, cardBean);
                        }
                    });
                } catch (Exception e) {
                    e.printStackTrace();
                }
                reader.close();
            }
        });
    }

    /**
     * 处理钱包数据
     *
     * @param positions 钱包在卡上的位置
     * @param data      钱包数据 json
     */
    private void onHandleWalletInfo(String[] positions, String[] data, CardBean cardBean) {
        NfcCommonUtils.handleCardWalletData(context, positions, data, cardBean);
        new CardDao(context).insertOrReplace(cardBean);
        if (mcStateListener != null) {
            mcStateListener.onAddSucceed();
        }
    }

    /**
     * 处理输入的数据
     *
     * @param sectorSize 扇区数量，一个扇区3条数据
     * @param startBlock 开始写入的扇区号
     * @return 是否成功
     */
    public boolean writeWallet(final String hexString, final int startBlock, final int sectorSize) {
        //区块编号,第一次是2扇区第一块04h号
        int k = startBlock;
        //正则，每16 * 2个分割
//        String[] stringArray = hexString.split("(?<=\\G................................)", 0);

        List<String> hexStringList = new ArrayList<>();
        for (int i = 0; i < 3 * sectorSize; i++) {
            hexStringList.add(hexString.substring(i * 32, (i + 1) * 32));
        }
        if (reader == null) {
            reader = Common.checkForTagAndCreateReader(context);
        }
        if (reader == null) {
            return false;
        }
        for (int i = 0; i < hexStringList.size(); i++) {

            //当startBlock扇区小于32时，是每四个为1秘钥区块
            //大于等于32时，16块为一
            if (startBlock < 128) {
                //每4个为秘钥区块，区块号+1, 验证，继续读写下一个扇区
                if (i % 3 == 0 && i > 0) {
                    k++;
                }
                if (!writeBlock(reader, k / 4, k % 4, hexStringList.get(i))) {
                    return false;
                }
            } else {
                if (!writeBlock(reader, (k - 128) / 15 + 32, (k - 128) % 15, hexStringList.get(i))) {
                    return false;
                }
            }

            k++;
        }
        return true;
    }

    /**
     * after a key map was created, this method tries to write the given
     * data to the tag. Possible errors are displayed to the user via Toast.
     */
    private boolean writeBlock(MCReader reader, int sector, int block, String data) {

        int result = -1;
        // Error while writing? Maybe tag has default factory settings ->
        // try to write with key a (if there is one).
//        if (result == -1 && keys[0] != null) {
        result = reader.writeBlock(sector, block,
                Common.hexStringToByteArray(data),
                Common.hexStringToByteArray(CHECK_KEY), false);
//        }
        // Error handling.
        switch (result) {
            case 2:
                return false;
            case -1:
                return false;
        }
        return true;
    }

    /**
     * 读取私钥
     *
     * @return 钱包数据
     */
    public String readWalletPrivKey(int position) {
        if (checkReaderNull()) {
            return "";
        }
        int sector = getSectorByPosition(position);
        try {
            final StringBuilder stringBuilder = new StringBuilder();
            if (sector < 32) {
                //前32个扇区，根据扇区号读写，连续四个扇区，12个区块
                for (int i = sector; i < sector + 5; i++) {
                    String readContent = reader.readSector(i, Common.hexStringToByteArray(CHECK_KEY), false);
                    stringBuilder.append(readContent);
                }
            } else {
                String readContent = reader.readSector(sector, Common.hexStringToByteArray(CHECK_KEY), false);
                stringBuilder.append(readContent);
            }
            return stringBuilder.toString();

        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 根据卡片已有的钱包位置，确定下一个钱包写入的位置
     *
     * @return 写入的区块位置position，如果超出返回-1
     */
    public int getInsertWalletPosition(List<CardWalletInfo> list) {
        int maxSector = reader.getSectorCount();
        return NfcCommonUtils.getInsertWalletPosition(maxSector, list);
    }


    public interface MCStateListener {

        void onAuthSuccess(String cardNo, String cardType);

        void onAddSucceed();

        void onAddedAlready();

        void onError(String error);
    }

    public void setMcStateListener(MCStateListener mcStateListener) {
        this.mcStateListener = mcStateListener;
    }

}
